home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
ASTEROID.ZIP
/
ASTEROID.C
next >
Wrap
C/C++ Source or Header
|
1994-07-10
|
7KB
|
273 lines
/*
* ASTEROID.C
*
* David Stafford
* Computer Shopper Magazine
* "What's the Code?"
* October 1994
*
* To build: BCC ASTEROID.C GRAPHICS.LIB
*/
#include <stdio.h>
#include <math.h>
#include <graphics.h>
#include <conio.h>
#include <dos.h>
typedef struct
{
float x, y; // 2D coordinates, a float so we can store fractional values
} POINT;
typedef struct
{
int NumPoints;
POINT Point[ 3 ]; // Three is enough for now but will have to make
} SHAPE; // this more flexible later.
typedef struct
{
POINT Loc; // Location on the screen
int ViewAngle; // Angle at which the object is facing
POINT Direction; // Direction which the object is moving, in pixels
SHAPE Shape; // The shape of the object
SHAPE Screen; // Actual points it occupies on the screen
} OBJECT;
struct
{
OBJECT Ship; // The players spaceship
} g;
// Translates a point by rotating it (using simple trig).
void TranslatePoint( POINT *Dest, POINT *Src, int Angle )
{
double Radians;
Radians = Angle * 0.01745;
Dest->x = Src->x * cos( Radians ) - Src->y * sin( Radians );
Dest->y = Src->x * sin( Radians ) + Src->y * cos( Radians );
}
// Translates an object's relative coordinates to actual
// screen coordinates.
void TranslateObject( OBJECT *Object )
{
int i;
for( i = 0; i < Object->Shape.NumPoints; i++ )
{
// First, account for rotation
TranslatePoint( &Object->Screen.Point[ i ], &Object->Shape.Point[ i ], Object->ViewAngle );
// Now make it relative to the screen location
Object->Screen.Point[ i ].x += Object->Loc.x;
Object->Screen.Point[ i ].y += Object->Loc.y;
}
}
// Goes through the list of points in an object
// and connects them all with lines.
void DrawObject( OBJECT *Object )
{
int i;
for( i = 1; i < Object->Shape.NumPoints; i++ )
{
line( Object->Screen.Point[ i - 1 ].x, Object->Screen.Point[ i - 1 ].y,
Object->Screen.Point[ i ].x, Object->Screen.Point[ i ].y );
}
line( Object->Screen.Point[ i - 1 ].x, Object->Screen.Point[ i - 1 ].y,
Object->Screen.Point[ 0 ].x, Object->Screen.Point[ 0 ].y );
}
// Moves an object along its direction.
void MoveObject( OBJECT *Object )
{
Object->Loc.x += Object->Direction.x;
Object->Loc.y += Object->Direction.y;
// Handle screen wrap-around
if( Object->Loc.x < 0 ) Object->Loc.x = Object->Loc.x + 640;
if( Object->Loc.x > 639 ) Object->Loc.x = Object->Loc.x - 640;
if( Object->Loc.y < 0 ) Object->Loc.y = Object->Loc.y + 480;
if( Object->Loc.y > 479 ) Object->Loc.y = Object->Loc.y - 480;
}
// This routine just waits until the display is
// in a vertical retrace cycle. This is useful
// for two things: to perform drawing during retrace
// when it can't be seen and (more importantly)
// to provide a method of synchronizing the animation
// with the game play so that it runs at a constant
// speed on virtually every machine.
void SyncToVerticalRetrace( void )
{
// If we happen to be in the middle of a vertical retrace
// period wait until its over.
while( inp( 0x3da ) & 8 )
;
// Wait until we begin vertical retrace.
while( !(inp( 0x3da ) & 8) )
;
}
#define ROTATE_STEP 3 // Number of degrees to rotate
#define SPEED 0.12 // Speed control
#define FRICTION 0.995 // Speed reduction per frame
void Supervisor( void )
{
unsigned short KeyboardStatus;
int c = 0, EraseFlag = 1, Color = WHITE;
while( c != 'q' && c != 'Q' )
{
TranslateObject( &g.Ship );
DrawObject( &g.Ship ); // Draw the ship
// Get the keyboard status bits from the BIOS data area
KeyboardStatus = *(unsigned short far *)MK_FP( 0x40, 0x17 );
MoveObject( &g.Ship );
// Simulate friction.
g.Ship.Direction.x *= FRICTION;
g.Ship.Direction.y *= FRICTION;
// If a real keystroke is waiting get it
if( kbhit() )
{
c = getch();
if( c == 'e' || c == 'E' )
{
EraseFlag = !EraseFlag; // Toggle erase flag
}
}
if( KeyboardStatus & 0x0002 ) // left shift, rotate left
{
g.Ship.ViewAngle -= ROTATE_STEP;
if( g.Ship.ViewAngle < 0 ) g.Ship.ViewAngle = 360 - ROTATE_STEP;
}
if( KeyboardStatus & 0x0001 ) // right shift, rotate right
{
g.Ship.ViewAngle += ROTATE_STEP;
if( g.Ship.ViewAngle > 359 ) g.Ship.ViewAngle = 0 + ROTATE_STEP;
}
if( KeyboardStatus & 0x4000 ) // shift-lock, fire
{
// Not supported yet.
}
if( KeyboardStatus & 0x0008 ) // alt, thrust
{
double Radians;
Radians = g.Ship.ViewAngle * 0.01745;
g.Ship.Direction.x += sin( Radians ) * SPEED;
g.Ship.Direction.y -= cos( Radians ) * SPEED;
}
SyncToVerticalRetrace(); // Pause until vertical retrace
if( EraseFlag ) DrawObject( &g.Ship ); // Erase the ship
if( c == 'c' || c == 'C' ) // Change color
{
Color ^= (WHITE ^ LIGHTGREEN);
setcolor( Color );
c = 0;
}
}
}
// Initialization code.
void Init( void )
{
int GraphicsDriver = VGA; // assume VGA graphics card
int GraphicsMode = VGAHI; // use VGA 640x480 16 color mode
initgraph( &GraphicsDriver, &GraphicsMode, NULL );
setwritemode( XOR_PUT );
g.Ship.Shape.NumPoints = 3;
g.Ship.Shape.Point[ 0 ].x = 0;
g.Ship.Shape.Point[ 0 ].y = -16;
g.Ship.Shape.Point[ 1 ].x = -8;
g.Ship.Shape.Point[ 1 ].y = +8;
g.Ship.Shape.Point[ 2 ].x = +8;
g.Ship.Shape.Point[ 2 ].y = +8;
g.Ship.ViewAngle = 0;
g.Ship.Loc.x = 320;
g.Ship.Loc.y = 240;
g.Ship.Direction.x = 0;
g.Ship.Direction.y = 0;
}
void Cleanup( void )
{
closegraph();
}
void main( int Argc, char *Argv[] )
{
puts( "\n\n" );
puts( "Asteroids. October 1994, \"What's the Code?\"\n" );
puts( "Left shift: Rotate left" );
puts( "Right shift: Rotate right" );
puts( "Alt: Thrust" );
puts( "E: Toggle 'erase' mode" );
puts( "C: Toggle color between white and green" );
puts( "Q: Quit\n" );
puts( "Press any key to begin..." );
getch();
Init();
Supervisor();
Cleanup();
}